package roborallyimplementation;
import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;



public class RoboTest {
	
	Robot zeroCoordinateRobot;
	Robot twoSeventyDegreesRobot;
	Robot zeroEnergyRobot;
	Robot oneEightyDegreesRobot;
	Robot sameSpotRobotA;
	Robot sameSpotRobotB;
	Robot sameHorizontalRobotA;
	Robot sameHorizontalRobotB;
	Robot sameVerticalRobotA;
	Robot sameVerticalRobotB;
	Robot insufficientEnergyRobotA;
	Robot insufficientEnergyRobotB;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
		zeroCoordinateRobot = new Robot (0, 0);
		twoSeventyDegreesRobot = new Robot(3, 3, 270, Robot.MAX_ENERGY);
		zeroEnergyRobot = new Robot(15, 15, 0, 0);
		oneEightyDegreesRobot = new Robot(0, 0, 180, Robot.MAX_ENERGY);
		sameSpotRobotA = new Robot(20, 20, 90, Robot.MAX_ENERGY);
		sameSpotRobotB = new Robot(20, 20, 180, Robot.MAX_ENERGY);
		sameHorizontalRobotA = new Robot(30, 30, 180, Robot.MAX_ENERGY);
		sameHorizontalRobotB = new Robot(30, 40, 0, Robot.MAX_ENERGY);
		sameVerticalRobotA = new Robot(50, 50, 90, Robot.MAX_ENERGY);
		sameVerticalRobotB = new Robot(40, 50, 270, Robot.MAX_ENERGY);
		insufficientEnergyRobotA = new Robot(0, 0, 90, 20000);
		insufficientEnergyRobotB = new Robot(100, 100, 270, 20000);
		
	}

	@After
	public void tearDown() throws Exception {
	}
	
	@Test(expected = IllegalPositionException.class)
	public void illegalPositionConstructorTest(){
		Robot test = new Robot(-1, -1, 0, 20000);
	}
	
	@Test
	public void completeConstructorTest(){
		Robot test = new Robot(0, 0, 180, 20000);
		assertEquals(0, test.getXCoordinate());
		assertEquals(0, test.getYCoordinate());
		assertEquals(180, test.getOrientation());
		assertEquals(20000, test.getEnergyLevel(), 0);
	}
	
	@Test
	public void totalOrientationConstructorTest(){
		Robot test = new Robot(0, 0, 150, 20000);
		assertEquals(0, test.getOrientation());
	}

	@Test
	public void zeroDegreesTo270DegreesTurn() {
		zeroCoordinateRobot.turnRight();
		assertEquals(270, zeroCoordinateRobot.getOrientation());
	}
	
	@Test
	public void twoSeventyDegreesTo0DegreesTurn(){
		twoSeventyDegreesRobot.turnLeft();
		assertEquals(0, twoSeventyDegreesRobot.getOrientation());
	}
	
	@Test
	public void turnRightTest(){
		twoSeventyDegreesRobot.turnRight();
		assertEquals(180, twoSeventyDegreesRobot.getOrientation());
	}
	
	@Test
	public void turnLeftTest(){
		assertTrue(zeroCoordinateRobot.canTurn());
		zeroCoordinateRobot.turnLeft();
		assertEquals(90, zeroCoordinateRobot.getOrientation());
	}
	
	@Test
	public void turnEnergyCostTest(){
		zeroCoordinateRobot.turnRight();
		assertEquals(19900, zeroCoordinateRobot.getEnergyLevel(), 0);
	}
	
	@Test
	public void rechargeBeyondMaxEnergy(){
		zeroCoordinateRobot.recharge(5000);
		assertFalse(Robot.isValidEnergyLevel(zeroCoordinateRobot.getEnergyLevel()));
	}
	
	@Test
	public void rechargeEnergyTest(){
		zeroEnergyRobot.recharge(5000);
		assertEquals(5000, zeroEnergyRobot.getEnergyLevel(), 0);
	}
	
	@Test
	public void energyPercentageTest(){
		zeroEnergyRobot.recharge(5000);
		assertEquals(25, zeroEnergyRobot.getEnergyPercentage(), 0);
	}
	
	@Test
	public void calculateEnergyRequiredTest()
	{
		assertEquals(1100, zeroCoordinateRobot.minEnergy(1, 1), 0.1);
		assertEquals(1200, zeroEnergyRobot.minEnergy(14, 14), 0.1);
		assertEquals(4200, sameHorizontalRobotA.minEnergy(35, 33), 0.1);
		assertEquals(10200 , sameVerticalRobotB.minEnergy(30, 40), 0.1);
		assertEquals(2500, zeroCoordinateRobot.minEnergy(5, 0), 0.1);
		assertEquals(10100, sameVerticalRobotA.minEnergy(40, 40), 0.1);
	}
	
	@Test(expected = IllegalPositionException.class)
	public void moveBeyondBoardBounds(){
		oneEightyDegreesRobot.move();
		assertEquals(-1, oneEightyDegreesRobot.getXCoordinate());
	}
	
	@Test
	public void isNextToTest(){
		sameSpotRobotA = new Robot(1, 1, 0 , 20000);
		sameSpotRobotB = new Robot(0, 0, 0, 20000);
		assertFalse(sameSpotRobotA.isNextTo(sameSpotRobotB));
	}
	
	@Test
	public void moveHorizontallyTest(){
		long currenty = zeroCoordinateRobot.getYCoordinate();
		zeroCoordinateRobot.move();
		assertEquals(1, zeroCoordinateRobot.getXCoordinate());
		zeroCoordinateRobot.turnRight();
		zeroCoordinateRobot.turnRight();
		zeroCoordinateRobot.move();
		assertEquals(0, zeroCoordinateRobot.getXCoordinate());
		assertTrue(zeroCoordinateRobot.isValidPosition(zeroCoordinateRobot.getCoordinates()));
		assertEquals(currenty, zeroCoordinateRobot.getYCoordinate());
		assertEquals(Robot.MAX_ENERGY - 1200, zeroCoordinateRobot.getEnergyLevel(), 0.1);
	}
	@Test
	public void moveVerticallyTest(){
		long currentx = zeroEnergyRobot.getXCoordinate();
		zeroEnergyRobot.recharge(Robot.MAX_ENERGY);
		assertTrue(Robot.isValidEnergyLevel(zeroEnergyRobot.getEnergyLevel()));
		assertTrue(zeroEnergyRobot.canMove());
		zeroEnergyRobot.turnLeft();
		zeroEnergyRobot.move();
		assertEquals(14, zeroEnergyRobot.getYCoordinate());
		zeroEnergyRobot.turnLeft();
		zeroEnergyRobot.turnLeft();
		zeroEnergyRobot.move();
		assertEquals(15, zeroEnergyRobot.getYCoordinate());
		assertTrue(zeroEnergyRobot.isValidPosition(zeroEnergyRobot.getXCoordinate(), zeroEnergyRobot.getYCoordinate()));
		assertEquals(currentx, zeroEnergyRobot.getXCoordinate());
		assertEquals(Robot.MAX_ENERGY - 1300, zeroEnergyRobot.getEnergyLevel(), 0.1);
	}
	
	@Test
	public void moveToRobotTest(){
		Robot guineaPigRobotA = new Robot(25, 25, 0, 20000);
		Robot guineaPigRobotB = new Robot(10, 10, 270, 20000);
		twoSeventyDegreesRobot.moveToOtherRobot(oneEightyDegreesRobot);
		assertTrue(twoSeventyDegreesRobot.isNextTo(oneEightyDegreesRobot));
		guineaPigRobotA.moveToOtherRobot(guineaPigRobotB);
		assertTrue(guineaPigRobotA.isNextTo(guineaPigRobotB));
	}
	
	@Test
	public void moveToRobotSameSpotTest(){
		sameSpotRobotA.moveToOtherRobot(sameSpotRobotB);
		assertTrue(sameSpotRobotA.isNextTo(sameSpotRobotB));
		assertEquals(19500, sameSpotRobotA.getEnergyLevel(), 0.1);
	}
	
	@Test
	public void moveToRobotSameSpotAtOriginTest(){
		sameSpotRobotA = new Robot(0, 0, 180, 20000);
		sameSpotRobotB = new Robot(0, 0, 90, 20000);
		sameSpotRobotA.moveToOtherRobot(sameSpotRobotB);
		assertTrue(sameSpotRobotA.isNextTo(sameSpotRobotB));
	}
	
	@Test
	public void moveToRobotSameSpotAtUpperBoundariesTest(){
		sameSpotRobotA = new Robot(sameSpotRobotA.getUpperXBound(), sameSpotRobotA.getUpperYBound());
		sameSpotRobotB = new Robot(sameSpotRobotB.getUpperXBound(), sameSpotRobotB.getUpperYBound());
		sameSpotRobotA.moveToOtherRobot(sameSpotRobotB);
		assertTrue(sameSpotRobotA.isNextTo(sameSpotRobotB));
	}
	
	@Test
	public void moveToRobotSameSpotAtUpperYBoundTest()
	{
		sameSpotRobotA = new Robot(sameSpotRobotA.getUpperXBound() / 2, sameSpotRobotA.getUpperYBound());
		sameSpotRobotB = new Robot(sameSpotRobotA.getXCoordinate(), sameSpotRobotA.getYCoordinate());
		sameSpotRobotA.moveToOtherRobot(sameSpotRobotB);
		assertTrue(sameSpotRobotA.isNextTo(sameSpotRobotB));
	}
	
	@Test
	public void moveToRobotSameHorizontalLocationTest(){
		sameHorizontalRobotA.moveToOtherRobot(sameHorizontalRobotB);
		assertTrue(sameHorizontalRobotA.isNextTo(sameHorizontalRobotB));
	}
	
	@Test
	public void moveToRobotSameVerticalLocationTest(){
		sameVerticalRobotA.moveToOtherRobot(sameVerticalRobotB);
		assertTrue(sameVerticalRobotA.isNextTo(sameVerticalRobotB));
	}
	
	@Test
	public void moveToRobotInsufficientEnergyTest(){
		insufficientEnergyRobotA.moveToOtherRobot(insufficientEnergyRobotB);
		assertFalse(insufficientEnergyRobotA.isNextTo(insufficientEnergyRobotB));
	}

}
